#include "hkx2dae.h"

hkx2dae::hkx2dae(string file)
{
	string filename = string(file + ".dae");
	root = dae.add(filename);
	this->file = file;
}

void hkx2dae::save()
{
	bool do_override = true;
	string filename = string(file + ".dae");
	dae.save(filename.c_str(), do_override);
}

domAsset *hkx2dae::addAsset(hkxScene *scene)
{
	// Add New Asset
	domAsset *asset = (domAsset *)root->add("asset");

	// Contributor Branch
	domAsset::domContributor *contributor = (domAsset::domContributor *) asset->add("contributor");
	domAsset::domContributor::domAuthor *author = (domAsset::domContributor::domAuthor *)contributor->add("author");
	domAsset::domContributor::domAuthoring_tool *tool = (domAsset::domContributor::domAuthoring_tool *)contributor->add("tool");
	domAsset::domContributor::domSource_data *data = (domAsset::domContributor::domSource_data *)contributor->add("source_data");

	// Misc
	domAsset::domCreated *created = (domAsset::domCreated *)asset->add("created");
	domAsset::domModified *modified = (domAsset::domModified *)asset->add("modified");
	domAsset::domUnit *unit = (domAsset::domUnit *)asset->add("unit");
	domAsset::domUp_axis *axis = (domAsset::domUp_axis *)asset->add("up_axis");

	author->setValue("unspecified");
	//tool->setValue(scene->m_modeller);
	//data->setValue(scene->m_asset);

	created->setValue("2010-03-30T12:00:00Z");
	modified->setValue("2010-03-30T12:00:00Z");
	unit->setMeter(0.01);
	unit->setName("centimeter");
	//axis->setValue();

	return asset;
}

domLibrary_geometries *hkx2dae::addLibraryGeometries(hkxScene *scene)
{
	domLibrary_geometries *library = (domLibrary_geometries *)root->add("library_geometries");

	for (int mesh = 0; mesh < scene->m_numMeshes; mesh++) {
		for (int section = 0; section < scene->m_meshes[mesh]->m_numSections; section++) {
			addGeometry(scene->m_meshes[mesh]->m_sections[section], library);
		}
	}

	return library;
}

//domLibrary_animations *hkx2dae::addLibraryAnimations(hkxScene *scene)
//{
//
//}

domLibrary_controllers *hkx2dae::addLibraryControllers(hkaAnimationContainer *container)
{
	domLibrary_controllers *library = (domLibrary_controllers *)root->add("library_controllers");

	for (int skeleton = 0; skeleton < container->m_numSkeletons; skeleton++) {
		
	}

	return library;
}

domLibrary_images *hkx2dae::addLibraryImages(hkxScene *scene)
{
	domLibrary_images *library;

	return library;
}

domGeometry *hkx2dae::addGeometry(hkxMeshSection *mesh_section, domLibrary_geometries *library)
{
	// Add New Geometry
	domGeometry *geometry = (domGeometry *)library->add("geometry");
	geometry->setId(string(file + "-lib").c_str());

	// Add Mesh
	domMesh *mesh = (domMesh *)geometry->add("mesh");

	// Data Sources
	domSource *positions;
	domSource *normals;
	domSource *texcoords;

	// Data Usage - What data sources are available.
	int data_usage = mesh_section->m_vertexBuffer->getVertexDesc()->getMask();

	// Sources
	if (data_usage & hkxVertexDescription::HKX_DU_POSITION) {
		positions = addSource(mesh, mesh_section->m_vertexBuffer, hkxVertexDescription::HKX_DU_POSITION);
	}
	if (data_usage & hkxVertexDescription::HKX_DU_NORMAL) {
		normals = addSource(mesh, mesh_section->m_vertexBuffer, hkxVertexDescription::HKX_DU_NORMAL);
	}
	if (data_usage & hkxVertexDescription::HKX_DU_TEXCOORD) {
		texcoords = addSource(mesh, mesh_section->m_vertexBuffer, hkxVertexDescription::HKX_DU_TEXCOORD);
	}

	// Vertices
	addVertices(mesh, positions);

	// Triangles
	for (int index = 0; index < mesh_section->m_numIndexBuffers; index++) {
		addTriangles(mesh, mesh_section->m_indexBuffers[index]);
	}

	// Add Material
	addMaterial(mesh_section->m_material, (domLibrary_materials *)root->add("library_materials"));

	return geometry;
}

domSource *hkx2dae::addSource(domMesh *mesh, hkxVertexBuffer *vertex_buffer, hkxVertexDescription::DataUsage data_usage)
{
	domSource *source = (domSource *)mesh->add("source");

	switch (data_usage) {
	case hkxVertexDescription::HKX_DU_POSITION:
		source->setId(std::string(file + "-lib-positions").c_str());
		break;
	case hkxVertexDescription::HKX_DU_NORMAL:
		source->setId(std::string(file + "-lib-normals").c_str());
		break;
	case hkxVertexDescription::HKX_DU_TEXCOORD:
		source->setId(std::string(file + "-lib-texcords").c_str());
		break;
	}

	domFloat_array* float_array = (domFloat_array *)source->add("float_array");

	switch (data_usage) {
	case hkxVertexDescription::HKX_DU_POSITION:
		float_array->setId(std::string(file + "-lib-positions-array").c_str());
		float_array->setCount(vertex_buffer->getNumVertices() * 3);
		break;
	case hkxVertexDescription::HKX_DU_NORMAL:
		float_array->setId(std::string(file + "-lib-normals-array").c_str());
		float_array->setCount(vertex_buffer->getNumVertices() * 3);
		break;
	case hkxVertexDescription::HKX_DU_TEXCOORD:
		float_array->setId(std::string(file + "-lib-texcords-array").c_str());
		float_array->setCount(vertex_buffer->getNumVertices() * 2);
		break;
	}

	unsigned int offset = vertex_buffer->getVertexDesc()->getElementByteOffset(data_usage, 0);
	unsigned int stride = vertex_buffer->getVertexDesc()->m_stride;

	for (int index = 0; index < vertex_buffer->getNumVertices(); index++) {
		float *value = reinterpret_cast<float *>(vertex_buffer->getVertexData() + (stride * index) + offset);

		switch (data_usage) {
		case hkxVertexDescription::HKX_DU_POSITION:
		case hkxVertexDescription::HKX_DU_NORMAL:
			float_array->getValue().append(value[0]);
			float_array->getValue().append(value[1]);
			float_array->getValue().append(value[2]);
			break;
		case hkxVertexDescription::HKX_DU_TEXCOORD:
			float_array->getValue().append(value[0]);
			float_array->getValue().append(value[1]);
			break;
		}
	}

	domTechnique *technique = (domTechnique *)source->add("technique_common");
	domAccessor *accessor = (domAccessor *)technique->add("accessor");

	accessor->setCount(vertex_buffer->getNumVertices());

	switch (data_usage) {
	case hkxVertexDescription::HKX_DU_POSITION:
		accessor->setSource(std::string("#" + file + "-lib-positions-array").c_str());
		accessor->setStride(3);
		break;
	case hkxVertexDescription::HKX_DU_NORMAL:
		accessor->setSource(std::string("#" + file + "-lib-normals-array").c_str());
		accessor->setStride(3);
		break;
	case hkxVertexDescription::HKX_DU_TEXCOORD:
		accessor->setSource(std::string("#" + file + "-lib-texcords-array").c_str());
		accessor->setStride(2);
		break;
	}

	domParam *param_x;
	domParam *param_y;
	domParam *param_z;
	domParam *param_s;
	domParam *param_t;

	switch (data_usage) {
	case hkxVertexDescription::HKX_DU_POSITION:
	case hkxVertexDescription::HKX_DU_NORMAL:
		param_x = (domParam *)accessor->add("param");
		param_x->setName("X");
		param_x->setType("float");
		param_y = (domParam *)accessor->add("param");
		param_y->setName("Y");
		param_y->setType("float");
		param_z = (domParam *)accessor->add("param");
		param_z->setName("Z");
		param_z->setType("float");
		break;
	case hkxVertexDescription::HKX_DU_TEXCOORD:
		param_s = (domParam *)accessor->add("param");
		param_s->setName("S");
		param_s->setType("float");
		param_t = (domParam *)accessor->add("param");
		param_t->setName("T");
		param_t->setType("float");
		break;
	}

	return source;
}

domVertices *hkx2dae::addVertices(domMesh *mesh, domSource *source)
{
	domVertices *vertices = (domVertices *)mesh->add("vertices");
	vertices->setId(std::string(file + "-lib-vertices").c_str());

	domInputLocal *input = (domInputLocal *)vertices->add("input");
	input->setSemantic("POSITION");
	input->setSource(std::string(std::string("#") + source->getID()).c_str());

	return vertices;
}

domTriangles *hkx2dae::addTriangles(domMesh *mesh, hkxIndexBuffer *index_buffer)
{
	domTriangles *triangles = (domTriangles *)mesh->add("triangles");
	//triangles->setMaterial();
	triangles->setCount(index_buffer->getNumTriangles());

	domInputLocal *input = (domInputLocal *)triangles->add("input");
	input->setSemantic("VERTEX");
	//input->setSource(std::string("#" + file + "-lib-vertices").c_str());
	//input->

	domP *p = (domP *)triangles->add("p");
	for (int index = 0; index < index_buffer->m_numIndices16; index++) {
		p->getValue().append(index_buffer->m_indices16[index]);
	}

	return triangles;
}

domMaterial *hkx2dae::addMaterial(hkxMaterial *hkx_material, domLibrary_materials *library)
{
	domMaterial *dom_material = (domMaterial *)library->add("material");
	dom_material->setId(hkx_material->m_name);

	domInstance_effect *effect = (domInstance_effect *)dom_material->add("instance_effect");
	effect->setUrl(string("#" + string(hkx_material->m_name) + "-fx").c_str());

	// Add Effect
	addEffect(hkx_material, (domLibrary_effects *)root->add("library_effects"));

	return dom_material;
}

domEffect *hkx2dae::addEffect(hkxMaterial *material, domLibrary_effects *library)
{
	domEffect *effect = (domEffect *)library->add("effect");
	effect->setId(string(string(material->m_name) + "-fx").c_str());

	domProfile_COMMON *profile = (domProfile_COMMON *)effect->add("profile_COMMON");

	domLibrary_images *library_images = (domLibrary_images *)root->add("library_images");

	// Reference images as domParam
	for (int stage = 0; stage < material->m_numStages; stage++) {
		hkVariant texture = material->m_stages[stage].m_texture;

		domImage *image;

		if (hkString::strCmp(texture.m_class->getName(), "hkxTextureFile") == 0) {
			image = addImage((hkxTextureFile *)texture.m_object, library_images);
		}
		else {
			// handle hkxTextureInplace
		}

		domParam *param = (domParam *)profile->add("newparam");
		//param->setSid(string(string(image->getId()) + "-surface").c_str());

		domFx_surface_common *surface = (domFx_surface_common *)param->add("surface");
		//surface->setType(
		domFx_surface_init_from_common *init_from = (domFx_surface_init_from_common *)surface->add("init_from");
		init_from->setValue(image->getId());
	}

	// Add technique
	//profile

	return effect;
}

domImage *hkx2dae::addImage(hkxTextureFile *texture_file, domLibrary_images *library)
{
	domImage *image = (domImage *)library->add("image");

	// Set the id, construct it if one doesn't exist
	if (texture_file->m_name != NULL) {
		image->setId(texture_file->m_name);
	}
	else if (texture_file->m_originalFilename != NULL) {
		image->setId(texture_file->m_originalFilename);
	}
	else {
		image->setId(getFileName(string(texture_file->m_filename)).c_str());
	}

	/// Add the init_from reference, assign it the filename
	domImage::domInit_from *init = (domImage::domInit_from *)image->add("init_from");
	init->setValue(texture_file->m_filename);

	return image;
}

